package com.apobates.forum.trident.controller;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.apobates.forum.attention.core.AvatarImagePathConvertHandler;
import com.apobates.forum.attention.core.ImageDirectoryEnum;
import com.apobates.forum.attention.core.ImagePathCoverter;
import com.apobates.forum.core.CommonTopic;
import com.apobates.forum.core.api.service.BoardService;
import com.apobates.forum.core.api.service.TopicActionCollectionService;
import com.apobates.forum.core.api.service.TopicService;
import com.apobates.forum.core.entity.Board;
import com.apobates.forum.core.entity.BoardStats;
import com.apobates.forum.core.entity.Topic;
import com.apobates.forum.core.entity.TopicActionCollection;
import com.apobates.forum.core.entity.TopicStats;
import com.apobates.forum.decorater.ForumEncoder;
import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.event.elderly.MemberActionDescriptor;
import com.apobates.forum.member.MemberProfileBean;
import com.apobates.forum.member.api.service.MemberActiveRecordsService;
import com.apobates.forum.member.api.service.MemberContactService;
import com.apobates.forum.member.api.service.MemberRealAuthenticationService;
import com.apobates.forum.member.api.service.MemberService;
import com.apobates.forum.member.api.service.MemberSocialInfoService;
import com.apobates.forum.member.entity.Member;
import com.apobates.forum.member.entity.MemberActiveRecords;
import com.apobates.forum.member.entity.MemberContact;
import com.apobates.forum.member.entity.MemberRealAuthentication;
import com.apobates.forum.member.entity.MemberSocialInfo;
import com.apobates.forum.member.storage.OnlineMemberStorage;
import com.apobates.forum.member.storage.core.MemberSessionBean;
import com.apobates.forum.trident.OnlineDescriptor;
import com.apobates.forum.trident.controller.form.MemberContactForm;
import com.apobates.forum.trident.controller.form.MemberPassportForm;
import com.apobates.forum.trident.controller.form.MemberProfileForm;
import com.apobates.forum.trident.controller.form.MemberRealnameAuthForm;
import com.apobates.forum.trident.controller.form.MemberSocialInfoForm;
import com.apobates.forum.trident.exception.ResourceNotFoundException;
import com.apobates.forum.trident.vo.ForumBoardStats;
import com.apobates.forum.trident.vo.ForumRankThread;
import com.apobates.forum.utils.Commons;
import com.apobates.forum.utils.DateTimeUtils;
import com.apobates.forum.utils.TipMessage;
import com.apobates.forum.utils.persistence.Page;
import com.apobates.forum.utils.persistence.PageRequest;
import com.google.gson.Gson;
/**
 * 会员管理中心控制器
 * 
 * @author xiaofanku@live.cn
 * @since 20190917
 */
@Controller
@RequestMapping(value = "/member/home")
public class MemberHomeController {
	@Autowired
	private ServletContext servletContext;
	@Autowired
	private MemberService memberService;
	@Autowired
	private MemberSocialInfoService memberSocialInfoService;
	@Autowired
	private MemberRealAuthenticationService memberRealAuthenticationService;
	@Autowired
	private MemberContactService memberContactService;
	@Autowired
	private TopicService topicService;
	@Autowired
	private TopicActionCollectionService topicActionCollectionService;
	@Autowired
	private BoardService boardService;
	@Autowired
	private OnlineMemberStorage onlineMemberStorage;
	@Autowired
	private MemberActiveRecordsService memberActiveRecordsService;
	@Value("${site.pageSize}")
	private int pageSize;
	@Value("${site.defat.avtar}")
	private String avatarDefaultDirect;
	@Value("${site.dec.salt}")
	private String globalDecSalt;
	private final static Logger logger = LoggerFactory.getLogger(MemberHomeController.class);
	
	// 会员中心|个人中心
	@GetMapping(path="/")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_HOME)
	public String getMemberHome(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		Member m = memberService.get(mbean.getMid()).orElseThrow(()->new ResourceNotFoundException("目标丢失或暂时无法访问"));
		model.addAttribute("token", token);
		//
		EnumMap<ForumActionEnum, Long> rawdata = topicActionCollectionService.groupMemberTopicAction(m.getId());
		MemberProfileBean memberProfile =  memberService.getMemberProfileBean(m.getId(), rawdata).orElse(MemberProfileBean.guest());
		Map<String,String> extInfoMap = new HashMap<>(3);
		//注册日期
		extInfoMap.put("logonDateTime", DateTimeUtils.formatClock(m.getRegisteDateTime()));
		//上次登录日期
		try{
			MemberActiveRecords lastLoginRecord = memberActiveRecordsService.getPreviousLoginRecord(mbean.getMid(), mbean.getNames()).orElse(null);
			String lldt = DateTimeUtils.formatClock(lastLoginRecord.getActiveDateTime());
			extInfoMap.put("prevLoginDateTime", lldt);
		}catch(NullPointerException e){
			extInfoMap.put("prevLoginDateTime", "-");
		}
		extInfoMap.put("names", mbean.getNames());
		model.addAttribute("member", memberProfile.toMergeMap(extInfoMap));
		return "default/home/index";
	}
	
	// 会员操作历史
	@GetMapping(path="/history")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_HISTORY)
	public String getMemberHistory(
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		model.addAttribute("total", Commons.optional(topicActionCollectionService.countByMember(mbean.getMid()), 0L));
		return "default/home/history";
	}

	@GetMapping(path="/history/rawdata", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String getMemberTopicActionHistory(
			@RequestParam("pageNumber") int page, 
			@RequestParam("pageSize")int pageSize, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		Page<TopicActionCollection> rs = topicActionCollectionService.getByMember(mbean.getMid(), new PageRequest(page, pageSize));
		List<ForumTopicActionRecord> data = rs.getResult().map(ForumTopicActionRecord::new).collect(Collectors.toList());
		//
		Map<String,Object> result = new HashMap<>();
		result.put("result", data);
		result.put("total", rs.getTotalElements());
		result.put("page", page);
		result.put("size", pageSize);
		Gson gson = new Gson();
		return gson.toJson(result);
	}

	// 会员信息
	@GetMapping(path="/profile")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_BASE)
	public String editMemberProfileForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberProfileForm form = new MemberProfileForm();
		
		form.setNickname(mbean.getNickname());
		form.setSignature(mbean.getSignature());
		form.setRecord(mbean.getMid());
		form.setToken(token); 
		model.addAttribute("form", form);
		return "default/home/profile";
	}

	@PostMapping(path="/profile")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_BASE)
	public String editMemberProfileAction(
			@ModelAttribute("form") MemberProfileForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			HttpServletResponse response, 
			Model model) {
		//无HTML tag,Emoji安全
		final String encodeSignatureContent = new ForumEncoder(form.getSignature()).noneHtmlTag().parseEmoji().getContent();
		boolean rmp = memberService.edit(mbean.getMid(), encodeSignatureContent, form.getNickname(), MemberActionDescriptor.getInstance(request, form.getToken())).isPresent();
		if (rmp) {
			mbean = mbean.refact(form.getNickname(), encodeSignatureContent);
			onlineMemberStorage.store(mbean, request, response);
			return "redirect:/member/home/profile";
		}
		model.addAttribute("form", form);
		//
		model.addAttribute("errors", "会员个人信息更新失败");
		return "default/home/profile";
	}

	// 社交信息
	@GetMapping(path="/social")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_SOCIAL)
	public String editMemberSocialInfoForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberSocialInfoForm form = new MemberSocialInfoForm();
		Optional<MemberSocialInfo> rmsi = memberSocialInfoService.getByMember(mbean.getMid());
		if (rmsi.isPresent()) {
			MemberSocialInfo msi = rmsi.get();
			form.setRecord(msi.getId());
			form.setQq(msi.getQq());
			form.setWeixin(msi.getWeixin());
			form.setWeibo(msi.getWeibo());
			form.setEmail(msi.getEmail()); // 解码
		}
		form.setToken(token); 
		model.addAttribute("form", form);
		return "default/home/social_info";
	}

	@PostMapping(path="/social")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_SOCIAL)
	public String editMemberSocialInfoAction(
			@ModelAttribute("form") MemberSocialInfoForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberActionDescriptor mad = MemberActionDescriptor.getInstance(request, form.getToken());
		Optional<MemberSocialInfo> rmsi;
		if (form.isUpdate()) {
			rmsi = memberSocialInfoService.edit(
					form.getLongRecord(), 
					mbean.getMid(), 
					mbean.getNames(), 
					"nobaba",
					form.getWeibo(), 
					form.getWeixin(), 
					form.getQq(), 
					form.getEmail(), 
					globalDecSalt, mad);
		} else {
			rmsi = memberSocialInfoService.create(
					mbean.getMid(), 
					mbean.getNames(), 
					"nobaba", 
					form.getWeibo(),
					form.getWeixin(), 
					form.getQq(), 
					form.getEmail(), 
					globalDecSalt, mad);
		}
		if (rmsi.isPresent()) {
			return "redirect:/member/home/profile";
		}
		model.addAttribute("form", form);
		//
		model.addAttribute("errors", "会员社交信息更新失败");
		return "default/home/social_info";
	}

	// 实名认证
	@GetMapping(path="/realauth")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_REALAUTH)
	public String editMemberRealnameAuthForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberRealnameAuthForm form = new MemberRealnameAuthForm();
		Optional<MemberRealAuthentication> rmra = memberRealAuthenticationService.getByMember(mbean.getMid());
		boolean isAuthed = false; // 未完成认证
		if (rmra.isPresent()) {
			MemberRealAuthentication mra = rmra.get();
			form.setRecord(mra.getId());
			form.setBirthYear(mra.getBirthYear());
			form.setBirthMonth(mra.getBirthMonth());
			form.setBirthDay(mra.getBirthDay());
			form.setRealname(mra.getRealname());
			form.setIdentityCard(mra.getIdentityCard()); // 解码
			isAuthed = mra.isPassed();
		}
		form.setToken(token); 
		model.addAttribute("form", form);
		model.addAttribute("isAuthed", isAuthed);
		return "default/home/realname_auth";
	}

	@PostMapping(path="/realauth")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_REALAUTH)
	public String editMemberRealnameAuthAction(
			@ModelAttribute("form") MemberRealnameAuthForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		Optional<MemberRealAuthentication> rmra;
		MemberActionDescriptor mad = MemberActionDescriptor.getInstance(request, form.getToken());
		if (form.isUpdate()) {
			rmra = memberRealAuthenticationService.edit(
					form.getLongRecord(), 
					mbean.getMid(), 
					form.getRealname(),
					form.getBirthYear(), 
					form.getBirthMonth(), 
					form.getBirthDay(), 
					form.getIdentityCard(), 
					globalDecSalt, mad);
		} else {
			rmra = memberRealAuthenticationService.create(
					mbean.getMid(), 
					form.getRealname(), 
					form.getBirthYear(),
					form.getBirthMonth(), 
					form.getBirthDay(), 
					form.getIdentityCard(), 
					globalDecSalt, mad);
		}
		if (rmra.isPresent()) {
			return "redirect:/member/home/profile";
		}
		model.addAttribute("form", form);
		model.addAttribute("isAuthed", false);
		//
		model.addAttribute("errors", "会员实名认证操作失败");
		return "default/home/realname_auth";
	}

	// 联系方式
	@GetMapping(path="/contact")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_CONTACT)
	public String editMemberContactForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberContactForm form = new MemberContactForm();
		Optional<MemberContact> rmc = memberContactService.getByMember(mbean.getMid());
		if (rmc.isPresent()) {
			MemberContact mc = rmc.get();
			form.setRecord(mc.getId());
			form.setProvince(mc.getProvince());
			form.setCity(mc.getCity());
			form.setRegion(mc.getRegion());

			form.setStreet(mc.getStreet());
			form.setPostcode(mc.getPostcode());
			form.setMobile(mc.getMobile()); // 解码
		}
		form.setToken(token);
		model.addAttribute("form", form);
		return "default/home/contact";
	}

	@PostMapping(path="/contact")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_CONTACT)
	public String editMemberContactAction(
			@ModelAttribute("form") MemberContactForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		Optional<MemberContact> rmc;
		MemberActionDescriptor mad = MemberActionDescriptor.getInstance(request, form.getToken());
		
		if (form.isUpdate()) {
			rmc = memberContactService.edit(
					form.getLongRecord(), 
					mbean.getMid(), 
					form.getProvince(), 
					form.getCity(),
					form.getRegion(), 
					form.getStreet(), 
					form.getPostcode(), 
					form.getMobile(), mad);
		} else {
			rmc = memberContactService.create(
					mbean.getMid(), 
					form.getProvince(), 
					form.getCity(), 
					form.getRegion(),
					form.getStreet(), 
					form.getPostcode(), 
					form.getMobile(), mad);
		}
		if (rmc.isPresent()) {
			return "redirect:/member/home/profile";
		}
		model.addAttribute("form", form);
		//
		model.addAttribute("errors", "会员联系方式更新失败");
		return "default/home/contact";
	}

	// 编辑登录密码
	@GetMapping(path="/passport")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PASSPORT)
	public String editMemberPswdForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		MemberPassportForm form = new MemberPassportForm();
		form.setToken(token); 
		model.addAttribute("form", form);
		return "default/home/password";
	}

	@PostMapping(path="/passport")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PASSPORT)
	public String editMemberPswdAction(
			@ModelAttribute("form") MemberPassportForm form, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		boolean result = memberService.editPswd(mbean.getMid(), form.getOldpswd(), form.getConfimpswd(), MemberActionDescriptor.getInstance(request, form.getToken())).orElse(false);
		if (result) {
			//--------------------------------------------------
			// 密码变化通知
			//--------------------------------------------------
			return "redirect:/member/home/passport/success.xhtml";
		}
		model.addAttribute("form", form);
		//
		model.addAttribute("errors", "会员密码更新失败");
		return "default/home/password";
	}

	@GetMapping(path="/passport/success.xhtml")
	public String passportSuccess(HttpServletRequest request, Model model) throws IllegalAccessException {
		//来源页判断 http Referer: site.domain{http://center.test.com}/member/home/passport
		String reqRef = request.getHeader("referer");
		if(null == reqRef || !reqRef.equals(onlineMemberStorage.getMetaConfig().getSite()+"/member/home/passport")){
			throw new IllegalAccessException("非法的请求路径");
		}
		return "default/home/password_success";
	}

	// 方案1
	// SpringBoot可以与SSM共存.
	// SpringBoot需要在war所在的目录放一个avatar文件夹(里面需要avatarTheme这个子文件夹,子文件夹中包含图片)
	private List<String> extractDirectFileNames(String avatarTheme) throws FileNotFoundException {
		Objects.requireNonNull(avatarTheme, "头像文件夹无法定位");
		final String fileRealPath = servletContext.getRealPath(avatarDefaultDirect + "/" + avatarTheme + "/");
		final String replaceString = onlineMemberStorage.getMetaConfig().getSite() + "/" + avatarDefaultDirect + "/"+ avatarTheme + "/";
		
		try {
			try (Stream<Path> sp = Files.list(Paths.get(fileRealPath))) {
				return sp.parallel().map((Path p) -> {
					return p.toAbsolutePath().toString().replace(fileRealPath, replaceString);
				}).filter(fn -> !fn.endsWith(".html")).collect(Collectors.toList());
			}
		} catch (IOException e) {
			if (logger.isDebugEnabled()) {
				logger.debug("头像文件夹遍历失败", e);
			}
		}
		return Collections.emptyList();
	}

	// 更改头像
	@GetMapping(path="/avatar")
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_AVATAR)
	public String editMemberAvatarForm(
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		// 没有自定义目录使用
		final String direct = "default";
		List<String> defaultAvatarImages = null;
		try{
			// 方案1
			defaultAvatarImages = extractDirectFileNames(direct);
		}catch (IOException e) {
			logger.info("[AVA]extract exception :"+e.getMessage());
		}
		if(null == defaultAvatarImages || defaultAvatarImages.isEmpty()){
			throw new ResourceNotFoundException("头像文件夹无法定位");
		}
		model.addAttribute("rs", defaultAvatarImages);
		model.addAttribute("token", token);
		// 当前选中的是哪一个
		model.addAttribute("active", AvatarImagePathConvertHandler.getDefaultAvtarFilePath(mbean.getAvatar()));
		return "default/home/avatar";
	}

	@PostMapping(path = "/avatar", produces = "application/json;charset=UTF-8")
	@ResponseBody
	@OnlineDescriptor(action=ForumActionEnum.MEMBER_PROFILE_AVATAR, isAjax=true)
	public TipMessage editMemberAvatarAction(
			@RequestParam("file") String avtarPath, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			HttpServletResponse response, 
			Model model) {
		// 编码头像地址
		String encodeAvtarFormatPath = new ImagePathCoverter(avtarPath).encodeAvatarPath(ImageDirectoryEnum.DEFAT); // 参数avtarpath='/default/xx.png';
		if (memberService.updateAvatar(mbean.getMid(), encodeAvtarFormatPath, MemberActionDescriptor.getInstance(request, token)).orElse(false)) {
			mbean = mbean.refact(encodeAvtarFormatPath);
			onlineMemberStorage.store(mbean, request, response);
			// 更新mbean中的图片
			return TipMessage.ofSuccess("头像更新成功");
		}
		return TipMessage.ofError("头像更新失败");
	}

	@GetMapping(path="/panel")
	public String getMemberMenu(
			@RequestParam("active")String currentMenu, 
			@RequestParam(value = "token", required = false, defaultValue = "0")String token, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		//---------------------------------------------是否来源自本站
		String requestRefString = request.getHeader("referer");
		if (null==requestRefString || !requestRefString.startsWith(onlineMemberStorage.getMetaConfig().getSite())) { // 只允许本站连接
			return "default/common/illegal_embed";
		}
		//---------------------------------------------
		model.addAttribute("manager", mbean.isManager());
		model.addAttribute("token", token);
		return "default/home/menu_embedded";
	}

	// 会员创建的话题
	@GetMapping(path="/topic")
	public String getMemberTopic(
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		model.addAttribute("total", Commons.optional(topicService.countAllForMember(mbean.getMid()), 0L));
		return "default/home/topic";
	}

	@GetMapping(path="/topic/rawdata", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String getMemberPublishTopices(
			@RequestParam("pageNumber") int page, 
			@RequestParam("pageSize")int pageSize, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		Page<Topic> rs = topicService.getAllForMember(mbean.getMid(), new PageRequest(page, pageSize));
		List<ForumActionRecord> data = rs.getResult().map(ForumActionRecord::new).collect(Collectors.toList());
		//
		Map<String,Object> result = new HashMap<>();
		result.put("result", data);
		result.put("total", rs.getTotalElements());
		result.put("page", page);
		result.put("size", pageSize);
		Gson gson = new Gson();
		return gson.toJson(result);
	}

	// 会员回复的话题
	@GetMapping(path="/posts")
	public String getMemberPosts(
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		model.addAttribute("total", Commons.optional(topicService.countAllForMemberReply(mbean.getMid()), 0L));
		return "default/home/posts";
	}

	@GetMapping(path="/posts/rawdata", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String getMemberReplyTopices(
			@RequestParam("pageNumber") int page, 
			@RequestParam("pageSize")int pageSize, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model) {
		Page<Topic> rs = topicService.getAllForMemberReply(mbean.getMid(), new PageRequest(page, pageSize));
		List<ForumActionRecord> data = rs.getResult().map(ForumActionRecord::new).collect(Collectors.toList());
		//
		Map<String,Object> result = new HashMap<>();
		result.put("result", data);
		result.put("total", rs.getTotalElements());
		result.put("page", page);
		result.put("size", pageSize);
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	// 会员收藏的话题
	@GetMapping(path="/topic/favorite")
	public String getMemeberFavoriteTopic(
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		model.addAttribute("total", Commons.optional(topicActionCollectionService.countAllByMemberAction(mbean.getMid(), ForumActionEnum.TOPIC_FAVORITE), 0L));
		return "default/home/topic_favorite";
	}

	@GetMapping(path="/topic/favorite/rawdata", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String getMemeberFavoriteTopicRawdata(
			@RequestParam("pageNumber") int page, 
			@RequestParam("pageSize")int pageSize, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		Page<TopicActionCollection> rs = topicActionCollectionService.getAllByMemberAction(mbean.getMid(), ForumActionEnum.TOPIC_FAVORITE, new PageRequest(page, pageSize));
		List<ForumTopicActionRecord> data = rs.getResult().map(ForumTopicActionRecord::new).collect(Collectors.toList());
		//
		Map<String,Object> result = new HashMap<>();
		result.put("result", data);
		result.put("total", rs.getTotalElements());
		result.put("page", page);
		result.put("size", pageSize);
		Gson gson = new Gson();
		return gson.toJson(result);
	}

	// 会员点赞的话题
	@GetMapping(path="/topic/like")
	public String getMemberLikeTopic(
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		model.addAttribute("total", Commons.optional(topicActionCollectionService.countAllByMemberAction(mbean.getMid(), ForumActionEnum.TOPIC_LIKED), 0L));
		return "default/home/topic_like";
	}

	@GetMapping(path="/topic/like/rawdata", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public String getMemberLikeTopicRawdata(
			@RequestParam("pageNumber") int page, 
			@RequestParam("pageSize")int pageSize, 
			MemberSessionBean mbean, 
			HttpServletRequest request, 
			Model model){
		Page<TopicActionCollection> rs = topicActionCollectionService.getAllByMemberAction(mbean.getMid(), ForumActionEnum.TOPIC_LIKED, new PageRequest(page, pageSize));
		List<ForumTopicActionRecord> data = rs.getResult().map(ForumTopicActionRecord::new).collect(Collectors.toList());
		//
		Map<String,Object> result = new HashMap<>();
		result.put("result", data);
		result.put("total", rs.getTotalElements());
		result.put("page", page);
		result.put("size", pageSize);
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	// 会员最近发布的话题
	@GetMapping(path = "/topic/publish/json", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public List<CommonTopic> getMemberRecentPublishTopic(
			@RequestParam("member") long memberId, 
			@RequestParam(value = "size", required = false, defaultValue = "5") int showSize, 
			HttpServletRequest request, 
			Model model) {
		int showRecordSize = (showSize>10 || showSize<1)?5:showSize;
		return topicService.getRecentForMember(memberId, showRecordSize).sorted(Comparator.comparing(Topic::getEntryDateTime).reversed()).map(CommonTopic::new).collect(Collectors.toList());
	}
	
	// 会员最近回复的话题
	@GetMapping(path = "/topic/reply/json", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public List<CommonTopic> getMemberRecentReply(
			@RequestParam("member") long memberId, 
			@RequestParam(value = "size", required = false, defaultValue = "5") int showSize, 
			HttpServletRequest request, 
			Model model) {
		int showRecordSize = (showSize>10 || showSize<1)?5:showSize;
		return topicService.getAllForMemberReply(memberId, showRecordSize).sorted(Comparator.comparing(Topic::getRankingDateTime).reversed()).map(CommonTopic::new).collect(Collectors.toList());
	}

	// 会员受欢迎的话题
	@GetMapping(path = "/topic/popular/json", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public List<ForumRankThread> getMemberPopularTopic(
			@RequestParam(value = "size", required = false, defaultValue = "5") int showSize, 
			MemberSessionBean mbean,
			HttpServletRequest request, 
			Model model) {
		int showRecordSize = (showSize > 10 || showSize < 1) ? 5 : showSize;
		Comparator<Topic> c = (Topic o1, Topic o2) -> {
			if (o1.getStats().getDisplaies() == o2.getStats().getDisplaies()) {
				return 0;
			}
			if (o1.getStats().getDisplaies() > o2.getStats().getDisplaies()) {
				return 1;
			}
			return -1;
		};
		AtomicInteger index = new AtomicInteger(0);
		Function<Topic, ForumRankThread> mapper = ts -> {
			int rk = index.getAndIncrement();
			return new ForumRankThread(ts, rk);
		};
		return topicService.getAllForMemberPopular(mbean.getMid(), showRecordSize).sorted(c.reversed()).map(mapper).collect(Collectors.toList());
	}

	// 会员活跃的版块
	// 会员星标的版块
	@GetMapping(path = "/board/active/json", produces = "application/json;charset=UTF-8")
	@ResponseBody
	public List<ForumBoardStats> getMemberStarBoard(
			@RequestParam("member") long memberId, 
			HttpServletRequest request, 
			@RequestParam(value = "size", required = false, defaultValue = "5") int showSize,
			Model model) {
		Function<Board, ForumBoardStats> action = (board) -> {
			if(null == board){
				return null;
			}
			BoardStats bs = Optional.ofNullable(board.getStats()).orElse(new BoardStats(board.getId(), board.getVolumesId()));
			return new ForumBoardStats(board, bs.getPostses(), bs.getTopices());
		};
		return boardService.getMemberFavorites(memberId, showSize).map(action).filter(Objects::nonNull).collect(Collectors.toList());
	}

	class ForumActionRecord{
		private final String title;
		private final String link;
		private final String publisher;
		private final String publisherURI;
		private final String publishDate;
		private final boolean reply;
		private final String replier;
		private final String replierURI;
		private final String replyDate;
		
		public ForumActionRecord(Topic topic){
			Objects.requireNonNull(topic);
			
			this.title = topic.getTitle();
			this.link = String.format("/topic/%s.xhtml", topic.getConnect());
			this.publisher = topic.getMemberNickname();
			this.publisherURI = String.format("/member/%s.xhtml", topic.getMemberId()+"");
			this.publishDate = DateTimeUtils.formatClock(topic.getEntryDateTime());
			TopicStats ts = topic.getStats();
			if(null != ts){
				this.replier = ts.getRecentPostsMemberNickname();
				this.replierURI = String.format("/member/%s.xhtml", ts.getRecentPostsMemberId()+"");
				this.replyDate = DateTimeUtils.formatClock(ts.getRecentPostsDate());
				this.reply = Commons.isNotBlank(ts.getRecentPostsMemberNickname())?true:false;
			}else{
				this.replier = "";
				this.replierURI = "";
				this.replyDate = "-";
				this.reply = false;
			}
		}
		public boolean isReply() {
			return reply;
		}
		public String getTitle() {
			return title;
		}
		public String getLink() {
			return link;
		}
		public String getPublisher() {
			return publisher;
		}
		public String getPublisherURI() {
			return publisherURI;
		}
		public String getPublishDate() {
			return publishDate;
		}
		public String getReplier() {
			return replier;
		}
		public String getReplierURI() {
			return replierURI;
		}
		public String getReplyDate() {
			return replyDate;
		}
	}
	class ForumTopicActionRecord{
		private final String title;
		private final String link;
		private final String action;
		private final String actionTitle;
		private final String actionDate;
		private final long id;
		
		public ForumTopicActionRecord(TopicActionCollection topicAction){;
			if(null != topicAction.getTopic()){
				this.link = String.format("/topic/%s.xhtml", topicAction.getTopic().getConnect());
			}else{
				this.link = "javascript:;";
			}
			this.title = topicAction.getTopicTitle();
			this.action = topicAction.getAction().name().toLowerCase().substring(6);
			this.actionTitle = topicAction.getAction().getTitle();
			this.actionDate = DateTimeUtils.formatClock(topicAction.getEntryDateTime());
			this.id = topicAction.getTopicId();
		}
		public String getTitle() {
			return title;
		}
		public String getLink() {
			return link;
		}
		public String getAction() {
			return action;
		}
		public String getActionDate() {
			return actionDate;
		}
		public long getId() {
			return id;
		}
		public String getActionTitle() {
			return actionTitle;
		}
	}
}
